/*
 * Map Class
 * 
 * Contains intermediate functions for external static functions and the repository
 */
package Track;

/**
 *
 * @author Chris
 */
public class Map {
    
    TransitSystem Sys;
    
    public Map(){
        Sys = new TransitSystem();
    }
    
    //id specifies head transition for id == 1, tail transition for id == 0
    //or retreive current head block info if id is anything else.
    //For transitions, info relating to the block the train is moving into will be returned
    protected RailInterface getRailInfo(int Train, int id){
        RailInterface RI;
        TrainInfo TI;
        Block tempBlock;
        TI = Sys.TrainList.get(Train);
        Line tempLine = Sys.LineList.get(TI.lineID);
        //Head Transition
        if (id == 1){
            tempBlock = tempLine.blockList.get(TI.nextHeadBlockID);
            //Standard case: The block after the current block is current.nextBlock
            if (TI.headBlockID != tempBlock.nextBlock.id){
                TI.previousHeadBlockID = TI.headBlockID;
                TI.headBlockID = TI.nextHeadBlockID;
                TI.nextHeadBlockID = tempBlock.nextBlock.id;
            }
            //Special case: the block after the current block is current.previousBlock
            //This allows two-directional travel on certain blocks
            else{
                TI.previousHeadBlockID = TI.headBlockID;
                TI.headBlockID = TI.nextHeadBlockID;
                TI.nextHeadBlockID = tempBlock.previousBlock.id; 
            }
            Sys.TrainList.set(Train, TI);
            //Break Track Circuit
            tempBlock.trackCircuitBroken = true;
            //Activate crossing if there is one in the block
            if (tempBlock.hasCrossing){
                tempBlock.Crossing.state = 1;
            }
            tempLine.blockList.set(tempBlock.id, tempBlock);
            Sys.LineList.set(TI.lineID, tempLine);
            
        }
        //Tail Transition
        else if (id == 0){
            tempBlock = tempLine.blockList.get(TI.nextTailBlockID);
            Block previousBlock = tempLine.blockList.get(TI.tailBlockID);
            //Standard case: The block after the current block is current.nextBlock
            if (TI.tailBlockID != tempBlock.nextBlock.id){
                TI.previousTailBlockID = TI.tailBlockID;
                TI.tailBlockID = TI.nextTailBlockID;
                TI.nextTailBlockID = tempBlock.nextBlock.id;
            }
            //Special case: the block after the current block is current.previousBlock
            //This allows two-directional travel on certain blocks
            else{
                TI.previousTailBlockID = TI.tailBlockID;
                TI.tailBlockID = TI.nextTailBlockID;
                TI.nextTailBlockID = tempBlock.previousBlock.id; 
            }
            Sys.TrainList.set(Train, TI);
            //Open track circuit
            previousBlock.trackCircuitBroken = false;
            if (tempBlock.hasCrossing){
                tempBlock.Crossing.state = 0;
            }
            tempLine.blockList.set(tempBlock.id, tempBlock);
            tempLine.blockList.set(tempBlock.id, previousBlock);
            Sys.LineList.set(TI.lineID, tempLine);
            
            
            
        }
        else tempBlock = tempLine.blockList.get(TI.headBlockID);
        
        RI = tempBlock.getRailInterface();
        
        return RI;
    }
    //Return a controllerInterface for the specified Block
    protected ControllerInterface getBlockData(int lineID, int blockID){
        Block tempBlock = getBlock(lineID, blockID);
        return tempBlock.getControllerInterface();
    }
    //Commit an updated ControllerInterface to the repository
    protected int setBlockData(int lineID, int BlockID, ControllerInterface updatedData){
        Line tempLine = Sys.LineList.get(lineID);
        Block tempBlock = tempLine.getBlock(BlockID);
        tempBlock.updateBlock(updatedData);
        return BlockID;
        
    }
    //Retreive a block
    protected Block getBlock(int lineID, int blockID){
        Line tempLine = Sys.LineList.get(lineID);
        Block tempBlock = tempLine.getBlock(blockID);
        return tempBlock;
        
    }
    //Set signal state
    protected int setSignal(int lineID, int blockID, int signalVal){
        Line tempLine = Sys.LineList.get(lineID);
        Block tempBlock = tempLine.getBlock(blockID);
        tempBlock.signalState = signalVal;
        tempLine.blockList.set(blockID, tempBlock);
        Sys.LineList.set(lineID, tempLine);
        return signalVal;
    }
    //Retreive Switch specified by switchID of Line lineID
    //If val param is different from the switches state switch the switch
    //and set the next and previous Block values for the affected Blocks appropriately.
    //Returns the id of the switches connectedBlock.
    //Setting val to -1 returns the id of the connected block without attempting to switch anything.
    protected int adjustSwitch(int switchID, int lineID, int val){
        
        
        //Get the Red or Green Line
        Line switchLine = Sys.LineList.get(lineID);
        //Retreive the specified switch from the lines switchList
        Switch currentSwitch = switchLine.switchList.get(switchID);
        
        //Check if the switch needs to be adjusted
        if (currentSwitch.state != val && val != -1){
            //Retreive the three blocks adjacent to the switch
            Block fixedBlock = this.getBlock(currentSwitch.line, currentSwitch.fixed);
            Block openBlock = this.getBlock(currentSwitch.line, currentSwitch.open);
            Block connectedBlock = this.getBlock(currentSwitch.line, currentSwitch.connected);

            //Check the Switches boolean variables to determine switch logic
            if (currentSwitch.loopSwitch && currentSwitch.nextConnect){
                fixedBlock.nextBlock = openBlock;
                openBlock.previousBlock = fixedBlock;
                connectedBlock.previousBlock = null;
            }
            else if(currentSwitch.loopSwitch){
                fixedBlock.previousBlock = openBlock;
                openBlock.previousBlock = fixedBlock;
                connectedBlock.nextBlock = null;
            }
            else if (currentSwitch.nextConnect){
                fixedBlock.nextBlock = openBlock;
                openBlock.previousBlock = fixedBlock;
                connectedBlock.previousBlock = null;
            }
            else{
                fixedBlock.previousBlock = openBlock;
                openBlock.nextBlock = fixedBlock;
                connectedBlock.nextBlock = null;

            }
            
            //Commit updated Blocks to the BlockList of the Line
            switchLine.blockList.set(fixedBlock.id, fixedBlock);
            switchLine.blockList.set(connectedBlock.id, connectedBlock);
            switchLine.blockList.set(openBlock.id, openBlock);
            
            //Update currentSwitch
            currentSwitch.state = val;
            int temp = currentSwitch.connected;
            currentSwitch.connected = currentSwitch.open;
            currentSwitch.open = temp;
            
            //Commit updated Switch to the SwitchList of the Line
            switchLine.switchList.set(switchID, currentSwitch);
            Sys.LineList.set(lineID, switchLine);
            
    
        }
        
        return currentSwitch.connected;
    }
    

    
}
